package edu.gmu.atelier.generic;

import edu.gmu.atelier.Epsilon;
import edu.gmu.atelier.Epsilon;

/**
 * Vector defined within some vector space.
 * @author James H. Pope
 */
public class RealVector <V extends Vector> implements Vector
{
    public double[] elements = null;
    
    
    public RealVector(double x, double y)
    {
        this.elements = new double[2];
        this.elements[0] = x;
        this.elements[1] = y;
    }
    
    public RealVector(double x, double y, double z)
    {
        this.elements = new double[3];
        this.elements[0] = x;
        this.elements[1] = y;
        this.elements[2] = z;
    }
    
    public RealVector(double c1, double c2, double c3, double c4)
    {
        this.elements = new double[4];
        this.elements[0] = c1;
        this.elements[1] = c2;
        this.elements[2] = c3;
        this.elements[3] = c4;
    }
    
    public RealVector(double[] elems)
    {
        this.elements = elems;
    }
    
    //------------------------------------------------------------------------//
    // Interface methods
    //------------------------------------------------------------------------//
    public double getElement(int i)
    {
        return this.elements[i];
    }
    
    public void setComponent(int i, double value)
    {
        this.elements[i] = value;
    }
    
    public int getLength()
    {
        return this.elements.length;
    }
    
    public void mult(double s)
    {
         for (int i = 0; i < elements.length; i++)
         {
            elements[i] *= s;
        }
    }
    
    public double dot(Vector v)
    {
        RealVector v2 = (RealVector)v;
        double dot = 0;
        for (int i = 0; i < this.elements.length; i++)
        {
            // implicitly v1 is transposed
            dot += this.elements[i] * v2.elements[i];
        }
        return dot;
    }
    
    public void add( Vector v )
    {
        RealVector o = (RealVector)v;
        for (int i = 0; i < elements.length; i++)
        {
            elements[i] += o.elements[i];
        }
    }
    
    public void multAdd(double scalar, Vector v)
    {
        RealVector o = (RealVector)v;
        for (int i = 0; i < elements.length; i++)
        {
            elements[i] += o.elements[i]*scalar;
        }
    }
    
    public RealVector copy()
    {
        double[] comps = new double[this.elements.length];
        for (int i = 0; i < comps.length; i++)
        {
            comps[i] = this.elements[i];
        }
        return new RealVector(comps);
    }
    
    public RealVector make()
    {
        return new RealVector(new double[this.elements.length]);
    }
    
    // Really a factory method, "this" is not used
    public RealVector make(int n)
    {
        return new RealVector(new double[n]);
    }
    
    //------------------------------------------------------------------------//
    // Class instance methods
    //------------------------------------------------------------------------//
    public boolean similar( Object obj, Epsilon e )
    {
        if(obj == this)
        {
            return true;
        }
        
        if( (obj instanceof RealVector) == false )
        {
            return false;
        }
        
        RealVector o = (RealVector)obj;
        
        if( o.elements.length != this.elements.length )
        {
            return false;
        }
        
        if( e != null )
        {
            for (int i = 0; i < this.elements.length; i++)
            {
                // Need epsilon check here
                //if( this.components[i] != o.components[i] )
                if( e.similar(this.elements[i], o.elements[i]) == false )
                {
                    return false;
                }
            }
        }
        else
        {
            for (int i = 0; i < this.elements.length; i++)
            {
                // Exact check, no epsilon specified
                if( this.elements[i] != o.elements[i] )
                {
                    return false;
                }
            }
        }
        
        return true;
    }
    
    public boolean equals( Object obj )
    {
        return this.similar(obj, null);
    }
    
    public String toString()
    {
        StringBuffer buf = new StringBuffer("[");
        for (int i = 0; i < elements.length; i++)
        {
            buf.append( elements[i]+"," );    
        }
        buf.append("]");
        return buf.toString();
    }
    
    //------------------------------------------------------------------------//
    // Static convenience methods
    //------------------------------------------------------------------------//
//    public static RealVector copy(RealVector v)
//    {
//        double[] comps = new double[v.components.length];
//        for (int i = 0; i < comps.length; i++)
//        {
//            comps[i] = v.components[i];
//        }
//        return new RealVector(comps);
//    }
//    
//    public static RealVector mult(RealVector v, double s)
//    {
//        /*
//         * Testing, since RealVector is immutable, no need to multiply if
//         * identity multiplier (i.e. 1.0), two benefits
//         * 1. Performance?
//         * 2. Round-off errors?
//         */
//        if( s == 1.0 )
//        {
//            return v;
//        }
//        if( s == 0.0 )
//        {
//            return new RealVector(new double[v.components.length]);
//        }
//        
//        double[] comps = new double[v.components.length];
//        for (int i = 0; i < comps.length; i++)
//        {
//            comps[i] = v.components[i]*s;
//        }
//        return new RealVector(comps);
//    }
//    
//    public static RealVector add(RealVector v1, RealVector v2)
//    {
//        double[] comps = new double[v1.components.length];
//        for (int c = 0; c < comps.length; c++)
//        {
//            comps[c] = v1.components[c] + v2.components[c];
//        }
//        return new RealVector(comps);
//    }
//    
//    public static RealVector add(RealVector[] vs)
//    {
//        double[] comps = new double[vs[0].components.length];
//        for (int i = 0; i < vs.length; i++)
//        {
//            RealVector v = vs[i];
//            for (int c = 0; c < comps.length; c++)
//            {
//                comps[c] += v.components[c];
//            }
//        }
//        return new RealVector(comps);
//    }
//    
//    public static double dot(RealVector v1, RealVector v2)
//    {
//        double dot = 0;
//        for (int i = 0; i < v1.components.length; i++)
//        {
//            // implicitly v1 is transposed
//            dot += v1.components[i] * v2.components[i];
//        }
//        return dot;
//    }
}
